package code;

import iterator.DuplElim;
import iterator.FileScanException;
import iterator.InvalidRelation;
import iterator.JoinsException;
import iterator.LowMemException;
import iterator.PredEvalException;
import iterator.Sort;
import iterator.SortException;
import iterator.TupleUtilsException;
import iterator.UnknowAttrType;
import iterator.WrongPermat;

import java.io.IOException;

import global.PageId;
import global.RID;
import heap.FieldNumberOutOfBoundException;
import heap.HFBufMgrException;
import heap.HFDiskMgrException;
import heap.HFException;
import heap.Heapfile;
import heap.InvalidSlotNumberException;
import heap.InvalidTupleSizeException;
import heap.InvalidTypeException;
import heap.Scan;
import heap.SpaceNotAvailableException;
import heap.TemporaryBasicPattern;
import heap.TemporaryTriple;
import heap.Triple;
import heap.Tuple;
import btree.Interface3;
import btree.RdbIndexType;
import bufmgr.PageNotReadException;

public class SortUtility {

	/**
	 * @param args
	 */

	public RdbIndexType orderType;
	public TemporaryTriple temptriple;
	public Interface3 i3;
	public Sort stream;
	public DuplElim noDuplStream;
	public Heapfile heapFile;
	public int [] sort_order = null;
	public int total_nodes = 0;
	public int confidenceColumn = 0;
	public int confidenceFlag = 0;
	
	public SortUtility (Interface3 i3) throws InvalidTypeException, InvalidTupleSizeException, IOException {
		this.i3 = i3;
		stream = null;
		noDuplStream = null;
		temptriple = new TemporaryTriple();
		orderType = null;
		heapFile = i3.temporaryHeap;
		
	}
	
	public SortUtility (Interface3 i3, int node, int total_nodes) throws InvalidTypeException, InvalidTupleSizeException, IOException {
		this.i3 = i3;
		stream = null;
		temptriple = new TemporaryTriple();
		orderType = null;
		heapFile = i3.temporaryHeap;
		this.total_nodes = total_nodes - 2;
		sort_order = new int [this.total_nodes]; 
		sort_order [0] = node;
		int scounter = 1;
		for (int i = 0; i < this.total_nodes; i++)
			if (i != node)
				sort_order [scounter++] = i;
		confidenceFlag = this.total_nodes-1;
		confidenceColumn = (this.total_nodes-1)*2+1;
		System.out.println("Col Index:" + confidenceColumn);
	}
	
	
	private RID extractRID (Tuple t, int pageIndex, int slotIndex) throws FieldNumberOutOfBoundException, IOException {
		int pid = t.getIntFld(pageIndex+1);
		int slot = t.getIntFld(slotIndex+1);
		return new RID (new PageId(pid), slot);
	}
	
	public void writeBPTuple (Tuple t) throws HFException, HFDiskMgrException, HFBufMgrException, Exception {
		TemporaryBasicPattern tempBP = TemporaryBasicPattern.getInstance(total_nodes);
		i3.TEMPORARY_TRIPLE_SIZE = (short) tempBP._tupleLength;
		RID rid;
		Tuple entityTuple;
		String entity;
		for (int i = 0; i < total_nodes; i++) {
			if (sort_order [i] == confidenceFlag)
				TemporaryBasicPattern.addString(tempBP, new Float (t.getFloFld(confidenceColumn)).toString());
			else {
				rid = extractRID(t, sort_order[i]*2, (sort_order[i]*2)+1);
			//	System.out.println("RID = "+rid);
				entityTuple = i3.entityHeap.getRecord(rid);
				entity = entityTuple.getStrFld(1);
				if (entity.length() > 49)
					entity = entity.substring(0, 48);
				TemporaryBasicPattern.addString(tempBP, entity);
			}
		}
		tempBP.setString();
		this.heapFile.insertRecord(tempBP.returnTupleByteArray());
	}
	
	public String [] nextSortedBPTuple (int buf_size) throws LowMemException, Exception {
		Tuple t;
		String [] returnString = new String [total_nodes];
		String data;
		String [] fields;
		if (noDuplStream == null) {
			noDuplStream = i3.getDuplicateEliminatedSortStream(buf_size);
		}
		t = noDuplStream.get_next();		
		if (t == null) {
			noDuplStream.close();
			noDuplStream = null;
			return null;
		}
		data = t.getStrFld(1);
		
		fields = data.split("\\^");
		for (int i = 0; i < total_nodes; i++) {
			returnString [sort_order[i]]= fields [i];
		}
		return returnString;
	}
	

	public void formatTriple(Triple triple, RdbIndexType orderOption
			) throws Exception {
		RID sid = triple.getSubjectID();
		RID pid = triple.getPredicateID();
		RID oid = triple.getObjectID();
		Tuple subjectTuple = i3.entityHeap.getRecord(sid);
		Tuple predicateTuple = i3.predicateHeap.getRecord(pid);		
		Tuple objectTuple = i3.entityHeap.getRecord(oid);
		String subject = subjectTuple.getStrFld(1);
		if(subject.length() > 49)
			subject = subject.substring(0,48 );
		String predicate = predicateTuple.getStrFld(1);
		if(predicate.length() > 49)
			predicate = predicate.substring(0,48 );
		String object = objectTuple.getStrFld(1);
		if(object.length() > 49){
			object = object.substring(0,48);
			System.out.println(object);
		}
		Float confidence = triple.getConfidence();
		switch (orderOption) {
		case SPO:
			temptriple.addTriple(subject, predicate, object,
					confidence.toString());
			orderType = RdbIndexType.SPO;
			break;
		case PSO:
			temptriple.addTriple(predicate, subject, object,
					confidence.toString());
			orderType = RdbIndexType.PSO;
			break;
		case SC:
			temptriple.addTriple(subject, confidence.toString(), predicate,
					object);
			orderType = RdbIndexType.SC;
			break;
		case PC:
			temptriple.addTriple(predicate, confidence.toString(), subject,
					object);
			orderType = RdbIndexType.PC;
			break;
		case OC:
			temptriple.addTriple(object, confidence.toString(), subject,
					predicate);
			orderType = RdbIndexType.OC;
			break;
		case C:
			temptriple.addTriple(confidence.toString(), subject, predicate,
					object);
			orderType = RdbIndexType.C;
			break;
		case SO:
			temptriple.addTriple(subject, object, predicate,
					confidence.toString());
			orderType = RdbIndexType.SO;
			break;
		case PO:
			temptriple.addTriple(predicate, object, subject,
					confidence.toString());
			orderType = RdbIndexType.PO;
			break;
		}
		this.heapFile.insertRecord(temptriple.returnTupleByteArray());
	}

	public String [] getNextSortedTriple(int buf_size)
			throws LowMemException, Exception {
		Tuple t;
		String [] returnString = new String [4];
		String data;
		String [] fields;
		if (stream == null) {
			stream = i3.getTemporarySortStream(buf_size);		
		}
		t = stream.get_next();		
		if (t == null) {
			stream.close();
			stream = null;
			return null;
		}
		data = t.getStrFld(1);
		//System.out.println(data);
		fields = data.split("\\^");
		switch (orderType) {
		case SPO:
			returnString [0] = fields [0];
			returnString [1] = fields [1];
			returnString [2] = fields [2];
			returnString [3] = fields [3];
			break;
		case PSO:
			returnString [0] = fields [1];
			returnString [1] = fields [0];
			returnString [2] = fields [2];
			returnString [3] = fields [3];
			break;
		case SC:
			int a;
			if (fields.length < 4)
				 a = 1;
			returnString [0] = fields [0];
			returnString [1] = fields [2];
			/*String objchk =null;
			System.out.println(fields[0]+" , "+fields[2]);
			if (fields[3]==null )
			objchk="not available";	
			else
				objchk=fields[3];*/
			returnString [2] = fields[3];
			returnString [3] = fields [1];
			break;
		case PC:
			returnString [0] = fields [2];
			returnString [1] = fields [0];
			/*objchk =null;
			if (fields[3]==null )
			objchk="not available";	
			else
				objchk=fields[3];*/
			returnString [2] = fields[3];
			returnString [3] = fields [1];
			break;
		case OC:
			returnString [0] = fields [2];
			returnString [1] = fields [3];
			returnString [2] = fields [0];
			returnString [3] = fields [1];
			break;
		case C:
			returnString [0] = fields [1];
			returnString [1] = fields [2];
			returnString [2] = fields [3];
			returnString [3] = fields [0];
			break;
		default:
			throw new Exception ("Unknown sort option");
		}
		return returnString;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
